package de.ret_world.eet.code;

import java.util.ArrayList;

/**
 * A CodeTable used to decrypt or encrypt data
 * @author Emu
 */
public class CodeTable {

    private Alphabet alphabet;
    private ArrayList[] table;

    /**
     * Creates a new CodeTable with the given Alphabet. The table is shuffled.
     * @param alphabet the alphabet to create the table
     */
    public CodeTable(Alphabet alphabet) {
        this.alphabet = alphabet;
        generateNewTable();
    }

    /**
     * Creates a new CodeTable by parsing the given CodeTable String. This is the same as <i>new CodeTable(alphabet).parseString(codetable);</i>
     * @param codetable The String representing the CodeTable
     */
    public CodeTable(String codetable) {
        parseCodeTable(codetable);
    }

    /**
     * Creates a new random CodeTable using the intern Alphabet
     */
    public final void generateNewTable() {
        table = new ArrayList[alphabet.getNumberOfSymbols()];
        if (alphabet != null && alphabet.getNumberOfSymbols() > 0) {
            for (int i = 0; i < table.length; i++) {
                table[i] = (ArrayList) alphabet.getShuffledAlphabet();
            }
        } else {
            throw new RuntimeException("Alphabet is not initialized or empty!");
        }
    }

    /**
     * @return the intern table
     */
    public ArrayList[] getTable() {
        return table;
    }

    /**
     * @return the used Alphabet
     */
    public Alphabet getAlphabet() {
        return alphabet;
    }

    /**
     * Do not use this method. Create a new instance of CodeTable instead.
     * @param alphabet 
     */
    public void setAlphabet(Alphabet alphabet) {
        this.alphabet = alphabet;
    }

    /**
     * Returns the Symbol from the given position in the CodeTable
     * @param col the column
     * @param row the row
     * @return the found Symbol
     */
    public Symbol getSymbol(int col, int row) {
        return (Symbol) table[row].get(col);
    }

    /**
     * Returns the Column of a given Symbol and its respective row.
     * @param row the row the given Symbol is in
     * @param symb the given Symbol
     * @return the column of the Symbol
     */
    public int getCol(int row, Symbol symb) {
        if (table[row].contains(symb)) {
            return table[row].indexOf(symb);
        }
        return -1;
    }

    /**
     * @return the height and width of the CodeTable
     */
    public int getTableSize() {
        return alphabet.getNumberOfSymbols();
    }

    /**
     * Returns a String representation of the CodeTable and all of its intern Objects. This can be used with "parseCodeTable()" to create a copy of this CodeTable.
     * @param seperator the seperating String of the Alphabet
     * @return the String representation
     */
    public String getCodeTableString(String seperator) {
        StringBuilder result = new StringBuilder();

        result.append(getSymbol(0, 0).getLength()).append("\n");
        result.append(getTableSize()).append("\n");
        result.append(seperator).append("\n");
        result.append(alphabet.getAlphabetString(seperator)).append("\n");
        for (int x = 0; x < getTableSize(); x++) {
            for (int y = 0; y < getTableSize(); y++) {
                result.append(getSymbol(y, x).toString());
            }
        }

        return result.toString();
    }

    /**
     * Parses a String to create a new CodeTable exactly likes the String describes it.
     * <br><br>
     * The String must have the following structure:<br>
     * First Line: Length of one Symbol <br>
     * Second Line: Length of the CodeTable <br>
     * Third Line: The seperator string <br>
     * Fourth Line: The String representing the alphabet <br>
     * Last Line: The CodeTable as a single line of all Symbols without breaks or seperation
     * @param codetable the representing String
     */
    public final void parseCodeTable(String codetable) {
        String[] lines = codetable.split("\\n");

        int symL = Integer.parseInt(lines[0]);
        int size = Integer.parseInt(lines[1]);
        String sep = lines[2];

        alphabet = new Alphabet(lines[3], sep);
        table = new ArrayList[alphabet.getNumberOfSymbols()];

        for (int i = 0; i < lines[4].length() / size; i++) {
            String seq = lines[4].substring(i * size, (i * size) + size);
            table[i] = new ArrayList();
            for (int l = 0; l < seq.length(); l++) {
                table[i].add(new Symbol(seq.substring(l * symL, (l * symL) + symL)));
            }
        }
    }
}
